package exam.springsecurity.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author Xiongx
 * @version 1.0
 * @date 2021/4/3 22:15
 * @since JDK 1.8
 */
@Configuration
@EnableWebSecurity
//添加annotation 支持,包括（prePostEnabled，securedEnabled...）
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.
                // 由于使用的是JWT，我们这里不需要csrf
                        csrf().disable()

                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()

                //所有用户可以访问"/resources"目录下的资源以及访问"/home"和favicon.ico
                .antMatchers("/resources/**", "/home","/**/favicon.ico","/auth/*","/**").permitAll()
                .antMatchers("/doc.html","/swagger-ui.html","/webjars/**"
                ,"/v2/**","/swagger-resources/**","/ruoyi/login.html","/ruoyi/**","/editor/**").permitAll()


                //以"/admin"开始的URL，并需拥有 "ROLE_ADMIN" 角色权限,这里用hasRole不需要写"ROLE_"前缀；
              //  .antMatchers("/admin/**").hasRole("ADMIN")
                //以"/admin"开始的URL，并需拥有 "ROLE_ADMIN" 角色权限和 "ROLE_DBA" 角色,这里不需要写"ROLE_"前缀；
               // .antMatchers("/dba/**").access("hasRole('ADMIN') and hasRole('DBA')")


                //.anyRequest().authenticated()//前面没有匹配上的请求，全部需要认证；
                .anyRequest().permitAll()

                .and()
                //指定登录界面，并且设置为所有人都能访问；
                //.formLogin() // 使用默认的登录页面
                .formLogin().loginPage("/ruoyi/login.html")
                .loginProcessingUrl("/login") //设置处理登陆提交的path
                //登入后跳转
                .successHandler(new AuthenticationSuccessHandler() {

                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        response.setContentType("application/json;charset=utf-8");
                      //  RequestCache cache = new HttpSessionRequestCache();
                       // SavedRequest savedRequest = cache.getRequest(request, response);
                       // String url = savedRequest.getRedirectUrl();
                       // response.sendRedirect(url);
                    }

                })
                .and().authorizeRequests()
                //.anyRequest().authenticated()

                //如果登录失败会跳转到"/logout"
                //.failureForwardUrl("/logout")

                .and()
                .logout()
                .logoutUrl("/admin/logout") //指定登出的地址，默认是"/logout"
                .logoutSuccessUrl("/home")   //登出后的跳转地址login?logout
                //自定义LogoutSuccessHandler，在登出成功后调用，如果被定义则logoutSuccessUrl()就会被忽略
                .invalidateHttpSession(true)  //定义登出时是否invalidate HttpSession，默认为true
                //.addLogoutHandler(logoutHandler) //添加自定义的LogoutHandler，默认会添加SecurityContextLogoutHandler
                .deleteCookies("usernameCookie","urlCookie") //在登出同时清除cookies
        ;

        // 禁用缓存
        http.headers().cacheControl();
        http.headers().frameOptions().disable(); //允许ifram嵌套

        // 添加JWT filter
     //   http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);


    }

    public static void main(String[] args) {
       String admin= new BCryptPasswordEncoder().encode("admin");
        System.out.println(admin);
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
                // 设置UserDetailsService
                .userDetailsService(this.userDetailsService)
                // 使用MD5进行密码的加密
                .passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        // 使用BCrypt加密密码
        return new BCryptPasswordEncoder();
    }




    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }


}

